﻿using System.Diagnostics;

namespace DimensionsHelper.LanguageService.Collections;

internal class ObjectPool<T>(int size, ObjectPool<T>.Factory factory)
    where T : class, new()
{
    public delegate T Factory();

    private readonly Element[] _elements = new Element[size];

    private T? _firstElement;


    public T Allocate()
    {
        T? instance = _firstElement;

        if (instance != null &&
            instance == Interlocked.CompareExchange(ref _firstElement, null, instance))
        {
            return instance;
        }

        for (int i = 0; i < _elements.Length; i++)
        {
            T? item = _elements[i].Value;
            if (item == null ||
                item != Interlocked.CompareExchange(ref _elements[i].Value, null, item))
            {
                continue;
            }

            instance = item;
            break;
        }

        instance ??= factory();
        return instance;
    }


    public void Free(T obj)
    {
        Debug.Assert(obj != null);
        Debug.Assert(_firstElement != null);

        if (_firstElement == null)
        {
            _firstElement = obj;
        }
        else
        {
            for (int i = 0; i < _elements.Length; i++)
            {
                if (_elements[i].Value != null)
                {
                    continue;
                }

                _elements[i].Value = obj;
                break;
            }
        }
    }


    private struct Element
    {
        public T? Value;
    }
}